﻿using ASmile.Extend;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;

namespace ASmile.Helpers
{
    public class HttpEasyAttribute : Attribute
    {
        public HttpEasyAttribute() { }

        public HttpEasyAttribute(string url)
        {
            Url = url;
        }

        public HttpEasyAttribute(string controllerName, string actionName)
        {
            Url = $"api/{controllerName}/{actionName}";
        }

        public string Url { set; get; }
    }

    /// <summary>
    /// 新 Http 实现，封装了 HttpEasy 的共通
    /// </summary>
    public abstract class HttpEasyDefault : HttpEasy
    {
        public HttpEasyDefault() { }

        public HttpEasyDefault(string rootUrl)
        {
            RootUrl = rootUrl;
        }

        public HttpEasyDefault(string rootUrl, string baseUrl)
        {
            RootUrl = rootUrl;
            BaseUrl = baseUrl;
        }

        protected abstract string ToJson(object obj);

        protected abstract TRet JsonToObject<TRet>(string json);

        /// <summary>
        /// action　前面的路径
        /// </summary>
        protected virtual string BaseUrl { get; set; }

        protected override void OnRequest(HttpWebRequest request)
        {
            base.OnRequest(request);
            PrintLog($"{request.Method} : {request.RequestUri}");
        }

        protected TRet PostRequestAction<TRet>(int frameIndex, params object[] args) where TRet : ApiResult, new()
        {
            StackTrace trace = new StackTrace();
            var frame = trace.GetFrame(frameIndex);
            var method = frame.GetMethod();
            var reqArg = ReflectionHelper.GetMethodAttribute<HttpEasyAttribute>(method, false);
            string url = null;
            if (reqArg != null && reqArg.Url.IsNotEmpty())
            {
                url = reqArg.Url;
            }

            if (url.IsEmpty())
            {
                var actionName = method.Name;
                url = UrlJoin(BaseUrl, actionName);
            }

            var parameterInfos = method.GetParameters();
            Dictionary<string, object> urlParamters = new Dictionary<string, object>();
            if (parameterInfos?.Length > 0 && parameterInfos.Length == args?.Length)
            {
                for (int i = 0; i < parameterInfos.Length; i++)
                {
                    var pInfo = parameterInfos[i];
                    var pValue = args[i];
                    if (pValue is string || (!pInfo.ParameterType.IsClass && pValue.GetType() == pInfo.ParameterType))
                    {
                        urlParamters[pInfo.Name] = pValue;
                    }
                }
            }
            if (urlParamters.Count > 0)
            {
                string paramters = "";
                foreach (var item in urlParamters)
                {
                    if (paramters.Length > 0)
                    {
                        paramters += "&";
                    }
                    if (item.Value is DateTime dt)
                    {
                        paramters += $"{item.Key}={dt:yyyy-MM-dd HH:mm:ss}";
                    }
                    else
                    {
                        paramters += $"{item.Key}={item.Value}";
                    }
                }

                url += "?" + paramters;
                return PostRequest<TRet>(url, null);
            }
            else
            {
                object body;
                if (args != null && args.Length > 0) body = args[0];
                else body = null;
                return PostRequest<TRet>(url, body);
            }
        }

        public TRet PostRequest<TRet>(string url, object jsonObj) where TRet : ApiResult, new()
        {
            string jsonBody = ToJson(jsonObj);
            PrintLog($"Body：\r\n{jsonBody}");
            var statusCode = Post(url, jsonBody, out string result);
            PrintLog($"Result：\r\n{result}");

            TRet ret;
            if (statusCode != 200)
            {
                string msg = result;
                return new TRet
                {
                    code = ApiResult.CODE_HTTP_FAIL,
                    msg = msg
                };
            }

            if (result.IsEmpty())
            {
                ret = new TRet
                {
                    code = ApiResult.CODE_HTTP_FAIL,
                    msg = $"请求服务器失败，返回内容为空"
                };
                PrintLog(ret.msg);
                return ret;
            }

            ret = JsonToObject<TRet>(result);
            if (ret == null)
            {
                ret = new TRet
                {
                    code = ApiResult.CODE_HTTP_FAIL,
                    msg = $"请求服务器失败，转换格式不正确"
                };
                PrintLog(ret.msg);

                return ret;
            }
            return ret;
        }

        protected TModel GetModel<TModel>(params object[] arg)
        {
            var ret = PostRequestAction<ApiResult<TModel>>(2, arg);
            return ret.data;
        }

        protected List<TList> GetList<TList>(out int total, params object[] arg) where TList : class, new()
        {
            var ret = PostRequestAction<ApiResultList<TList>>(2, arg);
            total = ret.count;
            return ret.data;
        }

        ////兼容原实现
        //[Obsolete("兼容原实现，改造代码后移除，请使用：GetList<TList>(out int total, params object[] arg)")]
        //protected List<TList> GetList<TList>(object arg, out int total) where TList : class, new()
        //{
        //    var ret = PostRequestAction<ApiResultList<TList>>(2, arg);
        //    total = ret.count;
        //    return ret.data;
        //}

        protected List<TList> GetList<TList>(params object[] arg) where TList : class, new()
        {
            var ret = PostRequestAction<ApiResultList<TList>>(2, arg);
            return ret.data;
        }

        protected ApiResult GetResult(params object[] arg)
        {
            return PostRequestAction<ApiResult>(2, arg);
        }

        protected ApiResult<T> GetResult<T>(params object[] arg)
        {
            return PostRequestAction<ApiResult<T>>(2, arg);
        }

        protected ApiResultList<T> GetResultList<T>(params object[] arg)
        {
            if (arg != null && arg.Length == 1 && arg[0] is ArgPageData pageArg && pageArg.IsCancelQuery)
            {
                return ApiResult.RetErrList<T>("客户端取消了查询");
            }
            return PostRequestAction<ApiResultList<T>>(2, arg);
        }
    }
}